use std::net::TcpStream;
use std::borrow::Cow;

use json;
use json::{Value};

use ws::{WebSocket, Message, Error, protocol::CloseFrame, protocol::frame::coding::CloseCode};

use super::{PieceColor, ChessPiece};
use super::{ChessAction};

///玩家初始棋子总数
pub const PIECE_COUNT: u8 = 9;

pub struct ChessPlayer{
    id: u32,
    pieces: u8,
    color: PieceColor,
    stream: WebSocket<TcpStream>,
}

impl ChessPlayer{
    pub fn new(id: u32, stream: WebSocket<TcpStream>) -> ChessPlayer{
        ChessPlayer{
            id,
            pieces: PIECE_COUNT,
            color: PieceColor::Black,
            stream
        }
    }

    ///获取玩家id
    pub fn id(&self) -> u32{
        self.id
    }

    ///玩家拿出一个棋子放到棋盘上
    pub fn take_piece(&mut self) -> Option<ChessPiece>{
        let pieces = self.pieces;
        if pieces == 0{
            None
        }else {
            let piece = ChessPiece::new(self.color.clone());
            self.pieces = pieces - 1;
            Some(piece)
        }
    }

    ///获取玩家棋子颜色
    pub fn color(&self) -> &PieceColor{
        &self.color
    }

    ///设置玩家棋子颜色
    pub fn set_color(&mut self, color: PieceColor){
        self.color = color;
    }

    ///玩家棋子是否放完了（手里是否还有棋子）
    pub fn no_piece(&self) -> bool {
        self.pieces == 0
    }

    ///接收玩家消息
    pub fn read_message(&mut self) -> Option<ChessAction> {
        let ret = self.stream.read_message();
        match ret {
            Ok(message) => {
                trace!("Receive one message from player: {}, data: {:?}", self.id, message);
                match message {
                    Message::Text(ref data) => self.parse_message(data),
                    Message::Binary(bytes) => {
                        unsafe {
                            let data = String::from_utf8_unchecked(bytes);
                            self.parse_message(data.as_str())
                        }
                    }
                    Message::Ping(_) |
                    Message::Pong(_) => None
                }
            },
            Err(e) => {
                error!("Receive message from connection {} error. {}", self.id, e);
                match e {
                    Error::ConnectionClosed(_) => {
                        Some(ChessAction::LoseConnection())
                    }
                    _ => None
                }
            }
        }
    }

    ///发送响应
    pub fn send_message(&mut self, message: String) {
        self.stream.write_message(Message::from(message));
    }

    ///解析json消息
    fn parse_message(&self, data: &str) -> Option<ChessAction>{
        let value = json::from_str(data).unwrap_or(Value::Null);
        if let Value::Null = value{
            return None;
        }
        let c = value.pointer("/code").unwrap_or(&Value::Null);
        if let &Value::Null = c{
            return None;
        }
        let code = c.as_str().unwrap_or("");
        match code {
            "chess_put" => {
                let data = value.pointer("/location").unwrap_or(&Value::Null);
                match data {
                    &Value::Number(ref n) => {
                        let location = n.as_u64().unwrap() as u8;
                        let action = ChessAction::PutPiece(location);
                        Some(action)
                    }
                    _ => None,
                }
            },
            "chess_kill" => {
                let data = value.pointer("/location").unwrap_or(&Value::Null);
                match data {
                    &Value::Number(ref n) => {
                        let location = n.as_u64().unwrap() as u8;
                        let action = ChessAction::KillPiece(location);
                        Some(action)
                    }
                    _ => None,
                }
            },
            //走子
            "chess_move" => {
                let s = value.pointer("/source").unwrap_or(&Value::Null);
                let t = value.pointer("/target").unwrap_or(&Value::Null);
                if let &Value::Null = s{
                    return None;
                }
                if let &Value::Null = t{
                    return None;
                }
                let source_loc = s.as_u64().unwrap_or(0);
                if 0 == source_loc{
                    return None;
                }
                let target_loc = t.as_u64().unwrap_or(0);
                if 0 == target_loc{
                    return None;
                }
                let source = source_loc as u8;
                let target = target_loc as u8;
                let action = ChessAction::MovePiece(source, target);
                Some(action)
            },
            "give_up" => {
                Some(ChessAction::GiveUp())
            },
            _ => {
                error!("Unsupported message code: {}", c);
                None
            },
        }
    }
}